package com.innovation.ic.cyz.base.service.cyz.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.innovation.ic.cyz.base.model.cyz.Mfr;
import com.innovation.ic.cyz.base.model.cyz.MfrContent;
import com.innovation.ic.cyz.base.model.cyz.MfrParam;
import com.innovation.ic.cyz.base.mapper.cyz.MfrMapper;
import com.innovation.ic.cyz.base.pojo.global.ServiceResult;
import com.innovation.ic.cyz.base.pojo.annotation.MfrParamCode;
import com.innovation.ic.cyz.base.pojo.constant.MfrModule;
import com.innovation.ic.cyz.base.pojo.variable.cyz.*;
import com.innovation.ic.cyz.base.pojo.variable.cyz.mfrsmt_search_option.MfrSmtOptionItem;
import com.innovation.ic.cyz.base.pojo.variable.cyz.mfrsmt_search_option.MfrSmtOptionLine;
import com.innovation.ic.cyz.base.service.cyz.MfrSmtService;
import com.innovation.ic.cyz.base.vo.cyz.MfrSmtListVo;
import lombok.var;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * smt厂家实现类
 */
@Service
@Transactional
public class MfrSmtServiceImpl extends ServiceImpl<MfrMapper, Mfr> implements MfrSmtService {

    @Resource
    private ServiceHelper serviceHelper;

    @Override
    public ServiceResult<MfrSmtListResultPojo> getList(MfrSmtListVo mfrListVo) throws NoSuchFieldException, IllegalAccessException {
        // 将查询的属性Id放到一起
        List<Long> paramIds = new ArrayList<>();
        if (mfrListVo.getFactoryFeatureIds() != null) {
            paramIds.addAll(mfrListVo.getFactoryFeatureIds());
        }
        if (mfrListVo.getQualificationIds() != null) {
            paramIds.addAll(mfrListVo.getQualificationIds());
        }
        if (mfrListVo.getTechnologyClassificationIds() != null) {
            paramIds.addAll(mfrListVo.getTechnologyClassificationIds());
        }
        if (mfrListVo.getQualityFeatureIds() != null) {
            paramIds.addAll(mfrListVo.getQualityFeatureIds());
        }

        // 根据注解的code, 获取所需要的MfrParam, 可以拿到MfrParamId
        var resModelCodes = getCodesFromClass(MfrSmtListPojo.class);
        var reqModelCodes = getCodesFromClass(MfrSmtListVo.class);
        List<String> allCodes = new ArrayList<>();
        allCodes.addAll(resModelCodes);
        allCodes.addAll(reqModelCodes);
        serviceHelper.getMfrParamDictionary().addCodes(MfrModule.SMT, allCodes);

        // 获取列表数据
        List<Long> mfrIds = serviceHelper.getMfrMapper().findMfrSmtIds(mfrListVo.getPage(), mfrListVo.getSize(),
                paramIds,
                serviceHelper.getMfrParamDictionary().getMfrParamIdByCode("company_name"),
                mfrListVo.getMfrName(),
                serviceHelper.getMfrParamDictionary().getMfrParamIdByCode("region"),
                mfrListVo.getRegionIds());
        Long mfrCount = serviceHelper.getMfrMapper().findMfrPcbCount(
                paramIds,
                serviceHelper.getMfrParamDictionary().getMfrParamIdByCode("company_name"),
                mfrListVo.getMfrName(),
                serviceHelper.getMfrParamDictionary().getMfrParamIdByCode("region"),
                mfrListVo.getRegionIds());

        List<MfrContent> mfrContentList = new ArrayList<>();
        if (mfrIds != null && !mfrIds.isEmpty()) {
            mfrContentList = serviceHelper.getMfrMapper().findMfrContentsByMfrIds(mfrIds, serviceHelper.getMfrParamDictionary().getMfrParamIdsByCodes(resModelCodes));
        }

        // 组合列表数据
        List<MfrSmtListPojo> mfrListPojoList = new ArrayList<>();
        for (Long mfrId : mfrIds) {
            MfrSmtListPojo mfrListPojo = new MfrSmtListPojo();
            mfrListPojo.setMfrId(mfrId);

            // 给加了注解的字段赋值
            Field[] fields = MfrSmtListPojo.class.getDeclaredFields();
            for (var field : fields) {
                var annotation = field.getAnnotation(MfrParamCode.class);
                if (annotation != null) {
                    MfrContent mfrContent = mfrContentList.stream()
                            .filter(t -> t.getMfrId().equals(mfrId) && t.getMfrParamId().equals(serviceHelper.getMfrParamDictionary().getMfrParamIdByCode(annotation.value())))
                            .findFirst().orElse(null);
                    if (mfrContent != null) {
                        Field f = mfrListPojo.getClass().getDeclaredField(field.getName());
                        f.setAccessible(true);
                        f.set(mfrListPojo, mfrContent.getContent());
                    }
                }
            }

            mfrListPojoList.add(mfrListPojo);
        }

        MfrSmtListResultPojo result = new MfrSmtListResultPojo();
        result.setList(mfrListPojoList);
        result.setTotal(mfrCount);

        ServiceResult<MfrSmtListResultPojo> serviceResult = new ServiceResult<MfrSmtListResultPojo>();
        serviceResult.setMessage(ServiceResult.SELECT_SUCCESS);
        serviceResult.setSuccess(Boolean.TRUE);
        serviceResult.setResult(result);

        return serviceResult;
    }

    @Override
    public ServiceResult<MfrSmtDetailPojo> getDetailById(Long mfrId) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        List<String> codes = getCodesFromClass(MfrSmtDetailPojo.class, MfrSmtProductPojo.class);
        serviceHelper.getMfrParamDictionary().addCodes(MfrModule.SMT, codes);

        List<MfrContent> mfrContentList = serviceHelper.getMfrMapper().findMfrContentsByMfrIds(new ArrayList<>(Arrays.asList(mfrId)), serviceHelper.getMfrParamDictionary().getMfrParamIdsByCodes(codes));

        MfrSmtDetailPojo mfrSmtDetailPojo = new MfrSmtDetailPojo();

        mfrSmtDetailPojo.setMfrId(mfrId);

        // 给加了注解的字段赋值
        Field[] fields = MfrPcbDetailPojo.class.getDeclaredFields();
        for (var field : fields) {
            var annotation = field.getAnnotation(MfrParamCode.class);
            if (annotation != null) {
                Field f = mfrSmtDetailPojo.getClass().getDeclaredField(field.getName());
                String typeName = f.getGenericType().getTypeName();
                if (typeName.equals("java.lang.String")) {
                    var content = getMfrContentByCode(mfrContentList, mfrId, annotation.value());
                    if (content != null) {
                        f.setAccessible(true);
                        f.set(mfrSmtDetailPojo, content.getContent());
                    }
                } else if (typeName.equals("java.util.List<java.lang.String>")) {
                    List<MfrContent> contents = getMfrContentsByCode(mfrContentList, mfrId, annotation.value());
                    if (contents != null && !contents.isEmpty()) {
                        List<String> stringList = contents.stream().map(MfrContent::getContent).collect(Collectors.toList());
                        f.setAccessible(true);
                        f.set(mfrSmtDetailPojo, stringList);
                    }
                } else if (typeName.matches("java.util.List<com.innovation.ic.cyz.base.pojo(\\w|\\.)+>")) {
                    Class<?> newClass = Class.forName(typeName.replace("java.util.List<", "").replace(">", ""));
                    var newClassCodes = getCodesFromClass(newClass);
                    List<MfrContent> contents = getMfrContentsByCodes(mfrContentList, mfrId, newClassCodes);
                    if (contents != null && !contents.isEmpty()) {
                        List<Object> newObjectList = new ArrayList<>();

                        Map<Integer, List<MfrContent>> collect = contents.stream().collect(Collectors.groupingBy(MfrContent::getGroupNo));
                        for (Map.Entry<Integer, List<MfrContent>> entry : collect.entrySet()) {
                            Object newObject = newClass.newInstance();
                            List<MfrContent> oneGroupContent = entry.getValue();

                            Field[] newClassFields = newObject.getClass().getDeclaredFields();
                            for (var newClassField : newClassFields) {
                                var newClassAnnotation = newClassField.getAnnotation(MfrParamCode.class);
                                if (newClassAnnotation != null) {
                                    var contentForNewClassField = getMfrContentByCode(oneGroupContent, mfrId, newClassAnnotation.value());
                                    if (contentForNewClassField != null) {
                                        newClassField.setAccessible(true);
                                        newClassField.set(newObject, contentForNewClassField.getContent());
                                    }
                                }
                            }

                            // 每个分组结束, 得到一个newObject
                            newObjectList.add(newObject);
                        }

                        f.setAccessible(true);
                        f.set(mfrSmtDetailPojo, newObjectList);
                    }
                }
            }
        }

        ServiceResult<MfrSmtDetailPojo> serviceResult = new ServiceResult<>();
        serviceResult.setMessage(ServiceResult.SELECT_SUCCESS);
        serviceResult.setSuccess(Boolean.TRUE);
        serviceResult.setResult(mfrSmtDetailPojo);
        return serviceResult;
    }

    /**
     * 查询列表选项
     *
     * @return
     */
    @Override
    public ServiceResult<List<MfrSmtOptionLine>> getListOptions() {
        List<String> bigOptionCodes = new ArrayList<>(Arrays.asList("factory_feature", "qualification", "process_category", "quality_feature"));
        List<MfrParam> level1_OptionMfrParamList = serviceHelper.getMfrParamMapper().findMfrParamsByCodes(MfrModule.SMT, bigOptionCodes);
        List<Long> level1_OptionMfrParamIds = level1_OptionMfrParamList.stream().map(MfrParam::getId).collect(Collectors.toList());
        List<MfrParam> level2_OptionMfrParamList = serviceHelper.getMfrParamMapper().findMfrParamsByParentIds(MfrModule.SMT, level1_OptionMfrParamIds);

        List<MfrSmtOptionLine> mfrSmtOptionLineList = new ArrayList<>();

        for (MfrParam level1_OptionMfrParam : level1_OptionMfrParamList) {
            var mfrPcbOptionLine = new MfrSmtOptionLine();

            // 第一级选项
            var level1_Option = new MfrSmtOptionItem();
            level1_Option.setMfrParamId(level1_OptionMfrParam.getId());
            level1_Option.setName(level1_OptionMfrParam.getName());
            mfrPcbOptionLine.setLevel1Option(level1_Option);

            // 第二级选项
            Long level1_OptionMfrParamId = level1_OptionMfrParam.getId();
            var level2_OptionMfrParamList_Filtered = level2_OptionMfrParamList.stream()
                    .filter(t -> t.getParentId() != null && t.getParentId().equals(level1_OptionMfrParamId)).collect(Collectors.toList());
            if (level2_OptionMfrParamList_Filtered != null && !level2_OptionMfrParamList_Filtered.isEmpty()) {
                var level2_Options = level2_OptionMfrParamList_Filtered.stream()
                        .map(item -> {
                            MfrSmtOptionItem level2_Option = new MfrSmtOptionItem();
                            level2_Option.setMfrParamId(item.getId());
                            level2_Option.setName(item.getName());
                            return level2_Option;
                        }).collect(Collectors.toList());
                mfrPcbOptionLine.setLevel2Options(level2_Options);
            }

            // 加到结果列表中
            mfrSmtOptionLineList.add(mfrPcbOptionLine);
        }

        ServiceResult<List<MfrSmtOptionLine>> serviceResult = new ServiceResult<>();
        serviceResult.setMessage(ServiceResult.SELECT_SUCCESS);
        serviceResult.setSuccess(Boolean.TRUE);
        serviceResult.setResult(mfrSmtOptionLineList);

        return serviceResult;
    }

    /**
     * 获取一个实体类中定义的MfrParamCode
     *
     * @param clazz
     * @return
     */
    private List<String> getCodesFromClass(Class<?>... clazz) {
        List<String> codes = new ArrayList<>();
        for (Class<?> cla : clazz) {
            Field[] fields = cla.getDeclaredFields();
            for (var field : fields) {
                var annotation = field.getAnnotation(MfrParamCode.class);
                if (annotation != null) {
                    codes.add(annotation.value());
                }
            }
        }
        return codes;
    }

    /**
     * 根据code获取MfrContent
     *
     * @param mfrContentList
     * @param mfrId
     * @param code
     * @return
     */
    private MfrContent getMfrContentByCode(List<MfrContent> mfrContentList, Long mfrId, String code) {
        return mfrContentList.stream()
                .filter(t -> t.getMfrId().equals(mfrId) && t.getMfrParamId().equals(serviceHelper.getMfrParamDictionary().getMfrParamIdByCode(code)))
                .findFirst().orElse(null);
    }

    /**
     * 根据code获取MfrContents
     *
     * @param mfrContentList
     * @param mfrId
     * @param code
     * @return
     */
    private List<MfrContent> getMfrContentsByCode(List<MfrContent> mfrContentList, Long mfrId, String code) {
        return mfrContentList.stream()
                .filter(t -> t.getMfrId().equals(mfrId) && t.getMfrParamId().equals(serviceHelper.getMfrParamDictionary().getMfrParamIdByCode(code)))
                .collect(Collectors.toList());
    }

    /**
     * 根据codes获取MfrContents
     *
     * @param mfrContentList
     * @param mfrId
     * @param codes
     * @return
     */
    private List<MfrContent> getMfrContentsByCodes(List<MfrContent> mfrContentList, Long mfrId, List<String> codes) {
        List<Long> mfrParamIds = serviceHelper.getMfrParamDictionary().getMfrParamIdsByCodes(codes);
        return mfrContentList.stream()
                .filter(t -> t.getMfrId().equals(mfrId) && mfrParamIds.contains(t.getMfrParamId()))
                .collect(Collectors.toList());
    }
}
